﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Data;
using System.Data.SqlClient;
using XemlUtilities.ISA.Protocol;
using XemlUtilities.DataSet;

namespace XemlUtilities.ISA
{
    class Assay : IsaTable
    {
        #region constructors
        private Assay(XemlDataSet xds, Guid xemlId, string connectionString)
            : base(xds)
        {
            DataColumn dcSampleName = new DataColumn("Sample Name", typeof(string));
            dcSampleName.AllowDBNull = false;
            this.Columns.Add(dcSampleName);
            foreach (DataRow item in this.Rows)
            {
                item[dcSampleName] = xds.SampleMapping.Single(x => x.FK_Sample == GetSampleId(item) && x.SubKey == "Chromatogram").Value;
            }

            foreach (MetaboliteExtraction extraction in ProtocolBase.GetProtocols().Where(x => x is MetaboliteExtraction))
            {

                this.AddProtocolRefColumn(extraction.Name);
                foreach (Parameter ExtractionParameter in extraction.GetParameters())
                {
                    if (ExtractionParameter.Name != null)
                    {
                        AddParameterValueColumn(ExtractionParameter.Name, ExtractionParameter.Value);
                    }

                    // ... there actually is no ontology information connection with this!
                    //if (ExtractionParameter.AccessionNr != null)
                    //{
                    //    AddTermAccessionNumberColumn(ExtractionParameter.AccessionNr.AccessionNr);
                    //    AddTermSourceREFColumn(ExtractionParameter.AccessionNr.Ontology.Name);
                    //}
                }
            }

            //Extract Name
            DataColumn dcExtractName = new DataColumn("Extract Name", typeof(string));
            dcExtractName.AllowDBNull = false;
            this.Columns.Add(dcExtractName);
            foreach (DataRow item in this.Rows)
            {
                item[dcExtractName] = xds.SampleMapping.Single(x => x.FK_Sample == GetSampleId(item) && x.SubKey == "Chromatogram").Value;
            }

            // Add the GcMs protocols
            foreach (GcMs gcMs in ProtocolBase.GetProtocols().Where(x => x is GcMs))
            {
                AddProtocolRefColumn(gcMs.Name);

                //this dictionary was intoduced to deal with an error secribed by kenneth as follows:
                //"What this bloody awful stacktrace is really trying to saying is that you cannot have two "Parameter Value[derivatisation]" columns in the same study."
                Dictionary<string, int> recurringTerms = new Dictionary<string, int>();
                foreach (var item in gcMs.GetParameters().GroupBy(x => x.Name).Select(x => new { name = x.Key, count = x.Count() }).Where(x => x.count > 1))
                {
                    recurringTerms.Add(item.name, 0);
                }

                foreach (Parameter gcMsParameter in gcMs.GetParameters())
                {
                    if (gcMsParameter.Name != null)
                    {
                        string name = recurringTerms.ContainsKey(gcMsParameter.Name) ? string.Concat(gcMsParameter.Name, "(", ++recurringTerms[gcMsParameter.Name],")") : gcMsParameter.Name;

                        AddParameterValueColumn(name, gcMsParameter.Value);
                    }

                    if (gcMsParameter.AccessionNr != null)
                    {
                        AddTermSourceREFColumn(gcMsParameter.AccessionNr.Ontology.Acronym);
                        AddTermAccessionNumberColumn(gcMsParameter.AccessionNr.AccessionNr);
                    }
                    else
                    {
                        AddTermSourceREFColumn(String.Empty);
                        AddTermAccessionNumberColumn(String.Empty);
                    }
                }
            }

            AddColumn("Labeled Extract Name", string.Empty);
            DataColumn dcMSAssayName = new DataColumn("MS Assay Name", typeof(String));
            dcMSAssayName.AllowDBNull = false; // can't be empty according to Reza Salek (see mail on 5th May 13)
            this.Columns.Add(dcMSAssayName);
            foreach (DataRow item in this.Rows)
            {
                item[dcMSAssayName] = item[dcSampleName];
            }

            using (Protocol.MetaboliteIdentification ident = new Protocol.MetaboliteIdentification())
            {
                this.AddProtocolRefColumn(ident.Name);
                //foreach (var item in ident.GetFactorValues())
                //{
                //    AddParameterValueColumn(item.Item1, truncate(item.Item2));
                //}
            }

            AddColumn("Normalization Name", string.Empty);
            AddColumn("Data Transformation Name", string.Empty);

            //Metabolite Assignment File
            AddColumn("Metabolite Assignment File", MetaboliteProfile.GetFileName(xds));
        }
        #endregion constructors

        public static MemoryStream GetStream(XemlDataSet xds, Guid xemlId, string connectionstring)
        {
            using (Assay dt = new Assay(xds, xemlId, connectionstring))
            {
                MemoryStream res = new MemoryStream();
                dt.Write(res);
                res.Seek(0, SeekOrigin.Begin);
                return res;
            }
        }

        public static string GetFileName(XemlDataSet xds)
        {
            return string.Format("a_{0}.txt", xds.Document.Single().PutativeFileName);
        }

        public string GetSampleName(int id)
        {
            return string.Concat("sample_", id);
        }

        string truncate(string s)
        {
            return s.Substring(0, Math.Min(s.Length, 250));
        }

        protected override void OnColumnChanged(DataColumnChangeEventArgs e)
        {
            base.OnColumnChanged(e);
            e.ProposedValue = this.escape(e.ProposedValue.ToString());
        }

        protected override void OnColumnChanging(DataColumnChangeEventArgs e)
        {
            base.OnColumnChanging(e);
            e.ProposedValue = this.escape(e.ProposedValue.ToString());
        }

    }
}
